#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/ioctl.h>
#include <sound/soc.h>
#include <sound/jack.h>

#define CMD_IOC_MAGIC	'a'
#define CMD_IOC_0		_IO(CMD_IOC_MAGIC, 0)
#define CMD_IOC_1		_IOR(CMD_IOC_MAGIC, 1, int)
#define CMD_IOC_2		_IOW(CMD_IOC_MAGIC, 2, int)

int flag_change=0;
static  char mybuf[100]="123";
static int strLength(const char *s);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("zz");

static dev_t devno;

static int demo_open(struct inode *ind, struct file *fp)
{
	printk("demo open\n");
	return 0;
}

static int demo_release(struct inode *ind, struct file *fp)
{
	printk("demo release\n");
	return 0;
}

static long demo_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
	int rc = 0;

	if (_IOC_TYPE(cmd) != CMD_IOC_MAGIC) {
		pr_err("%s: command type [%c] error.\n", __func__, _IOC_TYPE(cmd));
		return -ENOTTY;
	}

	switch(cmd) {
		case CMD_IOC_0:
			printk("cmd 0: no argument.\n");
			rc = 0;
			break;
		case CMD_IOC_1:
			flag_change=1;
			rc = 1;
			break;
		case CMD_IOC_2:
			flag_change=2;
			rc = 2;
			break;
		default:
			pr_err("%s: invalid command.\n", __func__);
			return -ENOTTY;
	}
	return rc;
}

static struct file_operations fops = {
	.open = demo_open,
	.release = demo_release,
	.unlocked_ioctl = demo_ioctl,
};

static struct cdev cd;

static int major;
static struct class *cls;

struct file_operations mytest_ops={
         .owner  = THIS_MODULE,
};

static ssize_t show_my_device(struct device *dev,
                  struct device_attribute *attr, char *buf)        //cat命令时,将会调用该函数
{

    char mybuf_temp[100]="123";
    int count1=0;
    int i;
    if(flag_change==1)
    {
    	return sprintf(buf, "%s\n", mybuf);
    }
    else if(flag_change==2)
    {
        count1=strLength(mybuf);
        for (i=0;i<count1;i++)
        {
        mybuf_temp[i]=mybuf[count1-1-i];
        }
        mybuf_temp[i]='\0';
    	return sprintf(buf, "%s\n", mybuf_temp);
    }
    else
    	return (-1);
}
static ssize_t set_my_device(struct device *dev,
                 struct device_attribute *attr,
                 const char *buf, size_t len)        //echo命令时,将会调用该函数
{
    sprintf(mybuf, "%s", buf);
    return len;
}
static DEVICE_ATTR(my_device_test, S_IWUSR|S_IRUSR, show_my_device, set_my_device);
                //定义一个名字为my_device_test的设备属性文件


static int demo_init(void)
{
	int rc;
	struct device *ioctl_test;  

	rc = alloc_chrdev_region(&devno, 0, 1, "test");
	if(rc < 0) {
		pr_err("alloc_chrdev_region failed!");
		return rc;
	}
	printk("MAJOR is %d\n", MAJOR(devno));
	printk("MINOR is %d\n", MINOR(devno));

	cdev_init(&cd, &fops);
	rc = cdev_add(&cd, devno, 1);
	if (rc < 0) {
		pr_err("cdev_add failed!");
		return rc;
	}


    major=register_chrdev(0,"mytest", &mytest_ops);
    cls=class_create(THIS_MODULE, "mytest_class");
    ioctl_test = device_create(cls, 0, MKDEV(major,0),NULL,"mytest_device");    //创建mytest_device设备    
    
    if(sysfs_create_file(&(ioctl_test->kobj), &dev_attr_my_device_test.attr)){    //在mytest_device设备目录下创建一个my_device_test属性文件
        return -1;}
            
    return 0;

}




/*计算字符串长度*/
static int strLength(const char *s)
{
	int len;
	len=0;
	while((*s)!=0)
	{
		s++;
		len++;
	}
	return len;
}
 

//end



static void demo_exit(void)
{
    device_destroy(cls, MKDEV(major,0));
    class_destroy(cls);
    unregister_chrdev(major, "mytest");
	
	cdev_del(&cd);
	unregister_chrdev_region(devno, 1);
	return;
}

module_init(demo_init);
module_exit(demo_exit);

